package org.x.note.protocol;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * [文件名称]<br>
 * FtpUtil <br>
 * <br>
 * [文件描述]<br>
 * FTP上传下载工具类，使用完之后需要关闭<br>
 * <br>
 * [修改记录]<br>
 * 2012-6-1 ver1.00 创建 xyl<br>
 * 
 * @author xyl
 * @version 1.00
 */
public class FtpUtil {

	/**
	 * log
	 */
	private static final Logger logger = LoggerFactory.getLogger(FtpUtil.class);

	private FTPClient ftp = new FTPClient();

	/**
	 * 连接FTP服务器
	 * 
	 * @param ip
	 *            FTP服务器IP
	 * @param port
	 *            端口
	 * @param userName
	 *            用户名
	 * @param password
	 *            密码
	 * @throws IOException
	 * @throws SocketException
	 */
	public void connectFTPServer(String ip, int port, String userName,
			String password) throws SocketException, IOException {
		ftp.configure(getFTPClientConfig());
		ftp.connect(ip, port);
		ftp.login(userName, password);

		// 文件类型,默认是ASCII
		ftp.setFileType(FTPClient.BINARY_FILE_TYPE);

		// 设置被动模式
		ftp.enterLocalPassiveMode();

		ftp.setConnectTimeout(2000);
		ftp.setControlEncoding("GBK");

		// 响应信息
		int replyCode = ftp.getReplyCode();
		if (!FTPReply.isPositiveCompletion(replyCode)) {
			// 关闭Ftp连接
			this.closeFTPClient();
			logger.error("登录FTP服务器{}:{}失败", new Object[] { ip, port });
		}
	}

	/**
	 * 配置FTP连接参数
	 * 
	 * @return
	 * @throws Exception
	 */
	private FTPClientConfig getFTPClientConfig() {
		// windows根据实际情况修改或增加判断
		String systemKey = FTPClientConfig.SYST_NT;
		String serverLanguageCode = "zh";
		FTPClientConfig conf = new FTPClientConfig(systemKey);
		conf.setServerLanguageCode(serverLanguageCode);
		conf.setDefaultDateFormatStr("yyyy-MM-dd");

		return conf;
	}

	/**
	 * 上传文件到FTP根目录
	 * 
	 * @param localPath
	 *            本地文件路径，以/结尾
	 * @param fileName
	 *            文件名
	 * @throws IOException
	 */
	public boolean uploadFile(String localPath, String fileName)
			throws IOException {
		InputStream input = null;
		try {
			input = new FileInputStream(new File(localPath + fileName));
		} catch (FileNotFoundException e) {
			throw e;
		} finally {
			if (input != null) {
				input.close();
			}
		}
		return uploadFile(input, fileName, File.separator);
	}

	/**
	 * 上传文件到FTP根目录
	 * 
	 * @param input
	 *            上传文件的输入流
	 * @param fileName
	 *            文件名
	 * @throws IOException
	 */
	public boolean uploadFile(InputStream input, String fileName)
			throws IOException {
		return uploadFile(input, fileName, File.separator);
	}

	/**
	 * 上传文件到指定的FTP路径下
	 * 
	 * @param localPath
	 *            本地文件路径，以/结尾
	 * @param fileName
	 *            文件名
	 * @param remotePath
	 *            FTP服务器的指定路径
	 * @throws IOException
	 */
	public boolean uploadFile(String localPath, String fileName,
			String remotePath) throws IOException {
		InputStream input = null;
		try {
			input = new FileInputStream(new File(localPath + fileName));
		} catch (FileNotFoundException e) {
			throw e;
		} finally {
			if (input != null) {
				input.close();
			}
		}
		return uploadFile(input, fileName, remotePath);
	}

	/**
	 * 上传文件到指定的FTP路径下
	 * 
	 * @param input
	 *            上传文件的输入流
	 * @param fileName
	 *            上传到FTP服务器之后的文件名
	 * @param remotePath
	 *            FTP服务器的指定路径
	 * @throws IOException
	 */
	public boolean uploadFile(InputStream input, String fileName,
			String remotePath) throws IOException {
		// 改变当前路径到指定路径
		this.changeDirectory(remotePath);
		return ftp.storeFile(fileName, input);
	}

	/**
	 * 从FTP服务器根路径下载文件
	 * 
	 * @param fileName
	 * @param localPath
	 * @return
	 * @throws IOException
	 */
	public boolean downloadFile(String fileName, String localPath)
			throws IOException {
		OutputStream output = null;
		try {
			output = new FileOutputStream(new File(localPath + fileName));
		} catch (FileNotFoundException e) {
			throw e;
		} finally {
			if (output != null) {
				output.close();
			}
		}

		return downloadFile(File.separator, fileName, localPath);
	}

	/**
	 * 从FTP服务器指定的路径下载文件
	 * 
	 * @param remotePath
	 *            FTP服务器的指定路径
	 * @param fileName
	 *            文件名
	 * @param localPath
	 *            本地路径，以/结尾
	 * @throws IOException
	 */
	public boolean downloadFile(String remotePath, String fileName,
			String localPath) throws IOException {
		OutputStream output = null;
		try {
			output = new FileOutputStream(new File(localPath + fileName));
		} catch (FileNotFoundException e) {
			throw e;
		} finally {
			if (output != null) {
				output.close();
			}
		}
		// 改变当前路径到指定路径
		this.changeDirectory(remotePath);
		return ftp.retrieveFile(fileName, output);
	}

	/**
	 * 获取FTP服务器根路径下文件的流
	 * 
	 * @param fileName
	 *            文件名
	 * @return
	 * @throws IOException
	 */
	public InputStream downloadFileStream(String fileName) throws IOException {
		return downloadFileStream(File.separator, fileName);
	}

	/**
	 * 获取FTP服务器指定的路径下文件的流
	 * 
	 * @param remotePath
	 *            FTP服务器的指定路径
	 * @param fileName
	 *            文件名
	 * @return
	 * @throws Exception
	 */
	public InputStream downloadFileStream(String remotePath, String fileName)
			throws IOException {
		// 改变当前路径到指定路径
		this.changeDirectory(remotePath);
		return ftp.retrieveFileStream(fileName);
	}

	/**
	 * 获取FTP服务器上指定路径下的文件列表
	 * 
	 * @param remotePath
	 * @return
	 * @throws IOException
	 */
	public List<String> getFileList(String remotePath) throws IOException {
		// 改变当前路径到指定路径
		ftp.changeWorkingDirectory(remotePath);
		FTPFile[] files = ftp.listFiles(remotePath);

		List<String> nlist = new ArrayList<String>();
		for (FTPFile file : files) {
			nlist.add(file.getName());
		}
		return nlist;
	}

	/**
	 * 改变工作目录，如失败则创建文件夹
	 * 
	 * @param newPath
	 * @throws IOException
	 */
	private void changeDirectory(String newPath) throws IOException {
		if (newPath != null) {
			boolean flag = ftp.changeWorkingDirectory(newPath);
			if (!flag) {
				ftp.makeDirectory(newPath);
				ftp.changeWorkingDirectory(newPath);
			}
		}
	}

	/**
	 * 关闭FTP连接
	 * 
	 * @throws IOException
	 */
	public void closeFTPClient() throws IOException {
		if (ftp.isConnected()) {
			ftp.disconnect();
		}
		ftp = null;
	}
}
